package com.cms.common.jpa;

import java.io.Serializable;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.Query;

/**
 * JPA通用DAO（Spring、JPA环境下使用）.
 * 
 * <ul>
 * <li>需在applicationContext.xml中将此类配置bean</li>
 * <li>并将EntityManager实现类注入entityManager属性</li>
 * </ul>
 * 
 * 相比hibernate：<br>
 * <ul>
 * <li>save()不返回ID、实现变化</li>
 * <li>update()会返回实体、实现变化</li>
 * <li>saveOrUpdate()不能实现</li>
 * <li>saveOrUpdateAll()不能实现</li>
 * <li>deleteAll()不能实现</li>
 * <li>getByExample()不能实现</li>
 * <li>findByExample()不能实现</li>
 * <li>find(int firstResult, int maxResults)不能实现</li>
 * <li>findByExample(int firstResult, int maxResults)不能实现</li>
 * <li>findByProperty(int firstResult, int maxResults)不能实现</li>
 * <li>load()不能实现</li>
 * <li>loadAll()不能实现</li>
 * <li>count()不能实现</li>
 * <li>countByProperty()不能实现</li>
 * </ul>
 */
@SuppressWarnings("unchecked")
public class JpaBaseDao <Tx, PKx extends Serializable> {
	/* ***************entityManager***************** */
	private EntityManager entityManager;
	public void setEntityManager(EntityManager entityManager) {
		this.entityManager = entityManager;
	}
	

	/** 
	 * 存储实体到数据库.
	 * <ul>
	 * <li>如果A是一个new状态的实体，它将会转为managed状态</li>
	 * <li>如果A是一个detached状态的实体，该方法会抛出IllegalArgumentException异常，具体异常根据不同的JPA实现有关</li>
	 * <li>如果A是一个managed状态的实体，它的状态不会发生任何改变。但是系统仍会在数据库执行INSERT操作</li>
	 * <li>如果A是一个removed状态的实体，它将会转换为受控状态</li>
	 * </ul>
	 */
	public <T> void save(T entity) {
		entityManager.persist(entity);
	}
	
	/** 删除指定的实体.
	 * <ul>
	 * <li>如果A是一个new状态的实例，A的状态不会发生任何改变，但系统仍会在数据库中执行DELETE语句</li>
	 * <li>如果A是一个detached状态的实体，该方法将会抛出异常</li>
	 * <li>如果A是一个managed状态的实例，它的状态会转换为removed</li>
	 * <li>如果A是一个removed状态的实例，不会发生任何操作</li>
	 * </ul>
	 */
	public <T> void delete(T entity) {
		entityManager.remove(entity);
	}
	
	/** 更新实体.
	 * <ul>
	 * <li>如果A是一个new状态的实体，该方法会产生一个根据A产生的managed状态实体A2</li>
	 * <li>如果A是一个detached状态的实体，该方法会将A的修改提交到数据库，并返回一个新的managed状态的实例A2</li>
	 * <li>如果A是一个managed状态的实体，它的状态不会发生任何改变。但是系统仍会在数据库执行UPDATE操作</li>
	 * <li>如果A是一个removed状态的实体，该方法会抛出IllegalArgumentException异常</li>
	 * </ul>
	 */
	public <T> T update(T entity) {
		return entityManager.merge(entity);
	}

	/** 根据主键获取实体，如果没有则返回null. */
	public <T> T get(Class<T> clazz, Serializable id) {
		return entityManager.find(clazz, id);
	}
	
	/** 根据属性查询. */
	public <T> T getByProperty(Class<T> clazz, String propertyName, Object value) {
		String jpql = new StringBuilder("select model from ").append(clazz.getName())
				.append(" model where model.").append(propertyName).append("= :propertyValue").toString();
		Query query = entityManager.createQuery(jpql);
		query.setParameter("propertyValue", value);
		List<T> list = query.getResultList();
		return list.size() > 0 ? list.get(0) : null;
	}
	
	/** 全部查询. */
	public <T> List<T> find(Class<T> clazz) {
		String jpql = new StringBuilder("select model from ").append(clazz.getName()).append(" model").toString();
		Query query = entityManager.createQuery(jpql);
		return query.getResultList();
	}
	
	/** 根据属性查询. */
	public <T> List<T> findByProperty(Class<T> clazz, String propertyName, Object value) {
		String jpql = new StringBuilder("select model from ").append(clazz.getName())
				.append(" model where model.").append(propertyName).append("= :propertyValue").toString();
		Query query = entityManager.createQuery(jpql);
		query.setParameter("propertyValue", value);
		return query.getResultList();
	}
	
}